#include "RemoteClient.h"
#include <string.h>

#ifdef __ANDROID__
#include <jni.h>
#include <android/log.h>
#define LOG_TAG "RemoteClient"
#define LOGI(message, ...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, "%s: " message, __FUNCTION__, ##__VA_ARGS__)
#define LOGW(message, ...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, "%s: " message, __FUNCTION__, ##__VA_ARGS__)
#define LOGE(message, ...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "%s: " message, __FUNCTION__, ##__VA_ARGS__)
#define LOGF(message, ...) __android_log_print(ANDROID_LOG_FATAL, LOG_TAG, "%s: " message, __FUNCTION__, ##__VA_ARGS__)

#define JNI_TRUE 1
#define JNI_FALSE 0

static JavaVM *gJavaVM = NULL;
static JNIEnv* env ;
static jclass callbackInterfaceClass = NULL;
MessageHandler* handler =NULL;

#ifdef __cplusplus
extern "C" {
#endif

JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
	gJavaVM = vm;
	LOGI("JNI_OnLoad");

	jint errcode = gJavaVM->GetEnv(reinterpret_cast<void**>(&env),
			JNI_VERSION_1_6);


	if (errcode != JNI_OK) {
		LOGW("GetEnv JNI_VERSION_1_6 return fail %d",errcode);
		return -1;
	}

	jclass tmp = env->FindClass(
			"com/post/bridge/client/RemoteClient");
	if (tmp == NULL) {
		LOGE("%s not be found", "com/post/bridge/client/RemoteClient");
		return -1;
	}
	callbackInterfaceClass = (jclass) env->NewGlobalRef(tmp);

	return JNI_VERSION_1_6;
}
int JNI_doBeforeUseJNI(){
	if (gJavaVM == NULL) {
		LOGW("'JavaVM' is null,had inkove 'System.loadLibrary()'?");
		return JNI_ERR;
	}
	if (env == NULL) {
		LOGW("'JavaEnv' is null");
		return JNI_ERR;
	}
	//通过JavaVM获取当前线程适用的JNIEnv，通过env返回。如果当前线程没有attach到Java环境里，那么env会被置为NULL，而GetEnv的返回值会是JNI_EDETACHED。
	int check = gJavaVM->GetEnv((void **) &env, JNI_VERSION_1_6);
//	LOGI("GetEnv ==: %d", check);
	if (check==JNI_EDETACHED) {
		LOGI("AttachCurrentThread");
		gJavaVM->AttachCurrentThread(&env, NULL);
	}
	if (callbackInterfaceClass == NULL) {
		LOGW("not find 'com/post/bridge/client/RemoteClient' class");
		return JNI_FALSE;
	}
	return check;
};
int JNI_doAfterUseJNI(int resultAtPre){
	if (gJavaVM == NULL) {
		LOGW("'JavaVM' is null,had inkove 'System.loadLibrary()'?");
		return JNI_FALSE;
	}
	if (env == NULL) {
		LOGW("'JavaEnv' is null");
		return JNI_FALSE;
	}
	if (resultAtPre == JNI_EDETACHED) {
		LOGI("DetachCurrentThread");
		int detach = gJavaVM->DetachCurrentThread();
	}
	return JNI_TRUE;
};
int sendByteMessage(int action, char* data, int dataLen) {
	int check = JNI_doBeforeUseJNI();
	if (check == JNI_ERR) {
		LOGW("'check JNI' have a error");
		return check;
	}
	jmethodID meth = env->GetStaticMethodID(callbackInterfaceClass,
			"sendByteMessage", "(I[B)I");
	if (meth == NULL) {
		LOGW("not find 'sendByteMessage' method");
		return JNI_FALSE;
	}

	jbyteArray jArray = env->NewByteArray(dataLen);
	env->SetByteArrayRegion(jArray, 0, dataLen, (jbyte*)data);

	jboolean result = env->CallStaticIntMethod(callbackInterfaceClass, meth,
			action,jArray);
	JNI_doAfterUseJNI(check);
	return 0;
}
int sendJSONMessage(const char* jsonMessage,int jsonMessageLen) {
	int check = JNI_doBeforeUseJNI();
	if (check == JNI_ERR) {
		LOGW("'check JNI' have a error");
		return check;
	}
	jmethodID meth = env->GetStaticMethodID(callbackInterfaceClass,
			"sendJSONMessage", "(Ljava/lang/String;)I");
	if (meth == NULL) {
		LOGW("not find 'sendJSONMessage' method");
		return JNI_FALSE;
	}
	jstring str1 = env->NewStringUTF(jsonMessage);
	jboolean result = env->CallStaticIntMethod(callbackInterfaceClass, meth,
			str1);
	JNI_doAfterUseJNI(check);
	return 0;
}

JNIEXPORT void JNICALL Java_com_post_bridge_client_RemoteClient_handleJSONMessage
(JNIEnv * env, jclass , jstring jsonMsg) {
	const char *json = env->GetStringUTFChars(jsonMsg, 0);
//	LOGI("json->%s ",json);
//	sendJSONMessage(json ,strlen(json));
	if(handler!=NULL){
		handler->handleJSONMessage(json,strlen(json));
	}
}

JNIEXPORT void JNICALL Java_com_post_bridge_client_RemoteClient_handleByteMessage
(JNIEnv * env, jclass, jint action, jbyteArray bytes) {
	jsize oldsize = env->GetArrayLength(bytes);
	int len = (int)oldsize;
	char* data = (char*)env->GetByteArrayElements(bytes, 0);
	// char*
//	LOGI("data->%s length:%d",data,len);
//	sendByteMessage(action,data,len );
	if(handler!=NULL){
		handler->handleByteMessage(action,data,len);
	}
}
int regitMessageHandler(MessageHandler* pHandler){
	if (pHandler == NULL) {
		return JNI_FALSE;
	}
	handler = pHandler;
}
#ifdef __cplusplus
}
#endif

#else // __ANDROID__
int sendByteMessage(int action, char* data, int dataLen){
	return -1;
}
int sendJSONMessage(const char* jsonMessage,int jsonMessageLen){
	return -1;
}
int regitMessageHandler(MessageHandler* handler){
	return -1;
}
#endif //__ANDROID__
